package com.le.tester.lock;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;

/**
 * createTime：2025-03-24 14:17
 * description：zkLock
 */
public class ZookeeperLock extends AbstractLock {

    public ZooKeeper zooKeeper;

    public String uuid;

    public String lockPath;

    //记录锁的重入次数
    private ConcurrentMap<Thread, Integer> threadLockCountMap = new ConcurrentHashMap<>();

    public ZookeeperLock(ZooKeeper zooKeeper, String lockName) {
        this.zooKeeper = zooKeeper;
        this.lockName = lockName;
        this.uuid = UUID.randomUUID().toString();
    }

    public String getBasePath() {
        return "/" + "distribute-lock";
    }

    public String getLockPath() {
        return getBasePath() + "/" + lockName;
    }

    private Watcher watcher = watchedEvent -> {
        //监听到变化了
        synchronized (ZookeeperLock.class) {
            ZookeeperLock.this.notify();
        }
    };

    @Override
    public void lock() {
        //临时节点加watch监听
        this.watchLock();
        if (threadLockCountMap.containsKey(Thread.currentThread())) {
            Integer lockCount = threadLockCountMap.get(Thread.currentThread());
            int resultCount = new AtomicInteger(lockCount).incrementAndGet();
            threadLockCountMap.put(Thread.currentThread(), resultCount);
            return;
        }
        //临时顺序节点加锁
        this.seqWatchLock();
        threadLockCountMap.put(Thread.currentThread(), 1);

    }

    public void seqWatchLock() {
        //1.创建顺序的临时节点
        try {
            String result = zooKeeper.create(getLockPath(), uuid.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            isFirstNode(result);
            lockPath = result;
        } catch (KeeperException | InterruptedException e) {
            e.printStackTrace();
        }

    }

    public void isFirstNode(String node) {
        while (true) {
            try {
                List<String> childrenList = zooKeeper.getChildren(getBasePath(), null);
                Collections.sort(childrenList);
                String[] split = node.split("/");
                int i = childrenList.indexOf(split[split.length - 1]);
                if (i > 0) {
                    //不是第一个的话，要监听上一个，等待上一个释放锁，再去唤醒获取锁
                    synchronized (this) {
                        zooKeeper.getData(getBasePath() + "/" + childrenList.get(i - 1), watcher, new Stat());
                        wait();
                    }
                }
                break;
            } catch (KeeperException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void watchLock() {
        //1.锁存在，zk会提示锁已经存在
        while (true) {
            try {
                String result = zooKeeper.create(getLockPath(), uuid.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
                //创建成功，跳出循环
                if ((getLockPath()).equals(result)) {
                    break;
                }
            } catch (KeeperException e) {
                //可以继续尝试获取锁
                try {
                    //睡的时间应该是上一把锁过期时间，能保证下次再获取的时候不是浪费时间去等待且不能发送无效的请求
                    //线程A锁释放了，线程B及时去请求获取锁，zk去监听锁被释放了
                    synchronized (this) {
                        byte[] data = zooKeeper.getData(getLockPath(), watcher, new Stat());
                        wait();
                    }
                    //Thread.sleep(100);
                } catch (Exception ignore) {
                }
            } catch (InterruptedException e) {
                break;
            }
            //2.锁的值为uuid，可以实现互斥
            //3.create temp node，防止死锁，等价于锁的过期时间
        }
    }

    @Override
    public void unlock() {

        try {
            if (threadLockCountMap.containsKey(Thread.currentThread())) {
                Integer currCount = threadLockCountMap.get(Thread.currentThread());
                int resultCount = new AtomicInteger(currCount).decrementAndGet();
                if (resultCount > 0) {
                    threadLockCountMap.put(Thread.currentThread(), resultCount);
                    return;
                }

                threadLockCountMap.remove(Thread.currentThread());
            }
//            byte[] lockVal = zooKeeper.getData(getLockPath(), null, new Stat());
            byte[] lockVal = zooKeeper.getData(lockPath, null, new Stat());
            //线程A拿到了线程A持有的锁
            if (uuid.equals(new String(lockVal))) {
                //zooKeeper.delete(getLockPath(), -1);
                zooKeeper.delete(lockPath, -1);
            }
        } catch (Exception ignore) {
            System.out.println("zk锁不存在，无需释放");

        }

    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public boolean tryLock() {
        return false;
    }

    @Override
    public Condition newCondition() {
        return null;
    }

}
